<?php
    # Skripti luo sovelluksesta jakelupaketin.
    #
    # HUOM! YUI Compressor vaatii Javan (>= 1.4).
    # -------------------------------------------
    
    # Aseta aikavyöhyke
    date_default_timezone_set("Europe/Helsinki");
    
    /**
     * Funktio käy lähdekansion läpi rekursiivisesti ja lisää sen alla olevat
     * kansiot ja tiedostot ZIP pakettiin.
     *
     * @param   ZipArchive  $zip    ZIP
     * @param   string      $source Lähdekansio
     */
    function addToZip(ZipArchive $zip,$source) {
        global $ignore,$tmp;
        
        foreach (scandir($source) as $row) {
            # Ohita
            if (in_array($row,$ignore)) {
                continue;
            }
            
            $sourceFile = $source.DIRECTORY_SEPARATOR.$row;
            
            # Lisää tiedosto
            if (is_file($sourceFile)) {
                $strlen = mb_strlen($tmp);
                $targetFile = $sourceFile;
                
                # Poista temppikansion polku kohdetiedoston alusta
                if (mb_substr($targetFile,0,$strlen) == $tmp) {
                    $targetFile = mb_substr($targetFile,$strlen+1);
                }
                
                $zip->addFile($sourceFile,$targetFile);
            } else if (is_dir($sourceFile)) { # Kansio -> käy läpi
                addToZip($zip,$sourceFile);
            }
        }
    }
    
    /**
     * Funktio kopioi lähdetiedoston kohdetiedostoon ja tekee tarvittaessa
     * PHP/JavaScript minimoinnin.
     *
     * @param   string  $source Polku lähdetiedostoon
     * @param   string  $target Polku kohdetiedostoon
     */
    function copyFile($source,$target) {
        global $php,$yui;
        
        $isWindows = false;
        if (mb_ereg_match("^WIN",mb_strtoupper(PHP_OS))) {
            $isWindows = true;
        }
        
        $basename = basename($source);
        $info = pathinfo($source,PATHINFO_EXTENSION);
        
        switch (mb_strtolower($info)) {
            case "css": # CSS
                # Tämä on jo minimoitu
                if (mb_ereg_match(".+\.min\.css$",mb_strtolower($basename))) {
                    $content = file_get_contents($source);
                } else { # Minimoi
                    $content = shell_exec(
                        "java -jar ".escapeshellarg($yui).
                        " ".escapeshellarg($source).
                        " --type css".
                        " --charset utf-8".
                        ((!$isWindows) ? " 2>&1" : "")
                    );
                    
                    # Minimointi epäonnistui
                    if (mb_ereg_match("^\[ERROR\]",trim($content))) {
                        throw new Exception("CSS MINIFY FAILED ($basename)!");
                    }
                }
                break;
            
            case "js": # JavaScript
                # Tämä on jo minimoitu
                if (mb_ereg_match(".+\.min\.js$",mb_strtolower($basename))) {
                    $content = file_get_contents($source);
                } else { # Minimoi
                    $content = shell_exec(
                        "java -jar ".escapeshellarg($yui).
                        " ".escapeshellarg($source).
                        " --type js".
                        " --charset utf-8".
                        ((!$isWindows) ? " 2>&1" : "")
                    );
                    
                    # Minimointi epäonnistui
                    if (mb_ereg_match("^\[ERROR\]",trim($content))) {
                        throw new Exception("JS MINIFY FAILED ($basename)!");
                    }
                }
                break;
            
            case "php": # PHP
                $content = shell_exec("$php -w ".escapeshellarg($source));
                break;
            
            default:
                $content = file_get_contents($source);
        }
        
        # Tiedoston sisältöä ei saada luettua
        if ($content === false) {
            throw new Exception("FAILED TO READ FILE CONTENT ($basename)!");
        }
        
        # Kopiointi epäonnistui
        if (file_put_contents($target,$content) === false) {
            throw new Exception("FILE COPY FAILED ($basename)!");
        }
    }
    
    /**
     * Funktio kopioi lähdekansion rekursiivisesti kohdekansioon.
     *
     * @param   string  $source Polku lähdekansioon
     * @param   string  $target Polku kohdekansioon
     */
    function copyFolder($source,$target) {
        global $ignore;
        
        # Tiedosto -> kopioi
        if (is_file($source)) {
            copyFile($source,$target);
        } else if (is_dir($source)) { # Kansio -> käy läpi
            # Luo kansio
            mkdir($target);
            
            foreach (scandir($source) as $row) {
                # Ohita
                if (in_array($row,$ignore)) {
                    continue;
                }
                
                $sourceFile = $source.DIRECTORY_SEPARATOR.$row;
                $targetFile = $target.DIRECTORY_SEPARATOR.$row;
                
                # Kyseessä on tiedosto -> kopioi
                if (is_file($sourceFile)) {
                    copyFile($sourceFile,$targetFile);
                } else if (is_dir($sourceFile)) { # Kyseessä on kansio -> käy läpi
                    copyFolder($sourceFile,$targetFile);
                }
            }
        }        
    }
    
    /**
     * Funktio kaiuttaa tekstin ruudulle ja tasaa sen perään välilyönnit
     *
     * @param   string  $txt    Teksti
     */
    function shellEcho($txt) {
        $strlen = mb_strlen($txt);
        echo $txt.str_repeat(".",(50-$strlen))." ";
    }
    
    /**
     * Funktio poistaa kansion rekusriivisesti.
     *
     * @param   string  $folder Polku kansioon
     */
    function unlinkFolder($folder) {
        if (is_dir($folder)) {
            foreach (scandir($folder) as $row) {
                # Ohita
                if (in_array($row,array(".",".."))) {
                    continue;
                }
                
                $file = $folder.DIRECTORY_SEPARATOR.$row;
                
                # Tiedosto -> poista            
                if (is_file($file)) {
                    unlink($file);
                } else if (is_dir($file)) { # Kansio -> käy läpi
                    unlinkFolder($file);
                }
            }
            rmdir($folder);
        }
    }
    
    # Paluukoodi
    $exitCode = 0;
    
    # PHP polku
    $php = "php";
    if (isset($_SERVER["_"])) {
        $php = $_SERVER["_"];
    }
    
    # YUI Compressor
    $yui = __DIR__.DIRECTORY_SEPARATOR."yuicompressor-2.4.8.jar";
    
    # Temppikansio
    $tmp = __DIR__.DIRECTORY_SEPARATOR.uniqid();
    
    # Nämä kansiot ohitetaan
    $ignore = array(
        ".",
        "..",
        ".svn"
    );
    
    # Kansiot/tiedostot jotka käydään läpi
    $folders = array(
        # Juuren .htaccess
        ".htaccess" => null,
        
        # Juuren .config
        ".config" => null,
        
        # API - kansio
        "API" => array(
            "3party",
            "class",
            "inc",
            "index.php",
            ".htaccess"
        ),
        
        # UI - kansio
        "UI" => array(
            "3party",
            "class",
            "css",
            "gateway",
            "img",
            "inc",
            "js",
            "view",
            "index.php"
        )            
    );
    
    try {
        # Aja testit    
        $runall = __DIR__.
            DIRECTORY_SEPARATOR.
            "API".
            DIRECTORY_SEPARATOR.
            "test".
            DIRECTORY_SEPARATOR.
            "runall.php";
        shellEcho("Running API tests (".basename($runall).")");
        
        $code = 0;
        $output = array();
        exec("$php ".escapeshellarg($runall),$output,$code);
        if ($code == 0) {
            echo "DONE!".PHP_EOL;
        } else {
            throw new Exception("FAILED!");
        }
        
        # Luo temppikansio
        shellEcho("Create temporary folder");
        if (mkdir($tmp)) {
            echo "DONE!".PHP_EOL;
        } else {
            throw new Exception("FAILED!");
        }
        
        # Käy kansiot läpi
        shellEcho("Copy and minify files");
        foreach ($folders as $root => $sub) {
            # Lähde
            $source = __DIR__.DIRECTORY_SEPARATOR.$root;
            # Kohde
            $target = $tmp.DIRECTORY_SEPARATOR.$root;
            
            if (is_file($source)) { # Tiedosto -> kopioi
                copyFile($source,$target);
            } else if (is_dir($source)) { # Kansio -> käy läpi
                # Luo kansio
                mkdir($target);
                
                # Käy alikansiot/tiedostot läpi
                foreach ((array)$sub as $subfile) {
                    copyFolder(
                        $source.DIRECTORY_SEPARATOR.$subfile,
                        $target.DIRECTORY_SEPARATOR.$subfile
                    );
                }
            }
        }
        echo "DONE!".PHP_EOL;
        
        # Luo ZIP paketti    
        $zipfile = __DIR__.DIRECTORY_SEPARATOR."gymdb-".date("Y-m-d-His").".zip";
        shellEcho("Create zip file");
            
        $zip = new ZipArchive();        
        if ($zip->open($zipfile,ZipArchive::CREATE) === true) {
            echo "DONE!".PHP_EOL;
        } else {
            throw new Exception("FAILED!");
        }
        
        # Lisää tiedostot ZIP pakettiin
        shellEcho("Add files and folders to zip file");
        addToZip($zip,$tmp);
        echo "DONE!".PHP_EOL;
        
        # Sulje ZIP paketti
        $zip->close();
    } catch (Exception $e) {       
        echo $e->getMessage().PHP_EOL;
        $exitCode = 1;
        
        # Sulje ZIP paketti
        if (isset($zip)) {
            $zip->close();
        }
        
        # Poista paketti
        if (isset($zipfile) && file_exists($zipfile)) {
            unlink($zipfile);
        }
    } finally {
        # Poista temppikansio
        shellEcho("Cleaning");
        unlinkFolder($tmp);
        echo "DONE!".PHP_EOL;
        
        # Paketti ok
        if (isset($zipfile) && file_exists($zipfile)) {
            echo PHP_EOL.
                "Packet is ready (".basename($zipfile).")!".
                PHP_EOL;
        }
    }
    
    exit($exitCode);